package com.yxsk.relay.job.component.admin.monitor;

import com.yxsk.relay.job.component.admin.monitor.callback.MonitorEventCallback;
import com.yxsk.relay.job.component.common.protocol.message.execute.JobExecuteResponse;
import com.yxsk.relay.job.component.common.utils.Assert;
import com.yxsk.relay.job.component.common.utils.CollectionUtils;
import com.yxsk.relay.job.component.common.vo.ExecuteResult;
import lombok.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author 11376
 * @CreaTime 2019/6/17 21:17
 * @Description
 */
public interface AsyncJobStatusMonitor {

    /**
     * @param
     * @Author 11376
     * @Description 启动监控
     * @CreateTime 2019/6/17 21:17
     * @Return
     */
    default void start() {
        this.reloadExecutingJob();
    }

    /**
     * @param
     * @Author 11376
     * @Description 重新加载正在执行的任务
     * @CreateTime 2019/6/22 23:22
     * @Return
     */
    void reloadExecutingJob();

    /**
     * @param
     * @Author 11376
     * @Description 停止监控
     * @CreateTime 2019/6/17 22:22
     * @Return
     */
    void stop();

    /**
     * @param monitorRequest
     * @Author 11376
     * @Description 任务监控请求
     * @CreateTime 2019/6/17 21:39
     * @Return
     */
    void monitor(MonitorRequest monitorRequest);

    /**
     * @param monitorRequest
     * @Author 11376
     * @Description 任务监控请求
     * @CreateTime 2019/6/17 21:39
     * @Return
     */
    void monitor(MonitorRequest monitorRequest, boolean soon);

    /**
     * @param monitorRequest 监控请求
     * @param executeTimeout 执行超时时间
     * @Author 11376
     * @Description 任务监控请求
     * @CreateTime 2019/6/19 13:55
     * @Return
     */
    void monitor(MonitorRequest monitorRequest, long executeTimeout);

    /**
     * @param monitorRequest 监控请求
     * @param executeTimeout 执行超时时间
     * @param soon 立即执行监控，加入此机制为了解决请求执行结束回调时间比加入监控列表更快，导致执行结果判断错误
     * @Author 11376
     * @Description 任务监控请求
     * @CreateTime 2019/6/19 13:55
     * @Return
     */
    void monitor(MonitorRequest monitorRequest, long executeTimeout, boolean soon);

    /**
     * @Author 1137
     * @Description 开始监控
     * @Date
     * @param jobId 任务id
     * @return 
     */
    void startMonitor(String jobId);

    /**
     * @Author 1137
     * @Description 放弃监控
     * @Date
     * @param jobId 任务id
     * @return
     */
    void giveUpMonitor(String jobId);

    /**
     * @param jobId 任务 Id
     * @Author 11376
     * @Description 撤销监控任务,
     * @CreateTime 2019/6/17 21:47
     * @Return
     */
    void repealMonitor(String jobId);

    /**
     * @param callbackInfo 任务任务回调
     * @Author 11376
     * @Description 任务完成回调
     * @CreateTime 2019/6/17 21:24
     * @Return
     */
    void doFinishCallback(JobExecuteCallbackInfo callbackInfo);

    @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    class MonitorRequest implements Cloneable {

        // 任务 id
        private String executeJobId;
        // 执行主机
        private String host;
        // 执行主机服务端口
        private Integer port;

        private String token;

        // 子任务监控
        private List<MonitorRequest> childrenJob;

        // 监控结果回调
        private MonitorEventCallback resultCallback = new MonitorEventCallback() {

            private Logger log = LoggerFactory.getLogger(MonitorEventCallback.class);

            @Override
            public void onFinish(String jobId, JobExecuteResponse executeResponse) {
                if (log.isInfoEnabled()) {
                    log.info("Job execute complete, job id: [{}], execute result: [{}]", jobId, executeResponse);
                }
            }

            @Override
            public void onError(String jobId, Throwable e) {
                log.error(MessageFormat.format("Job execute error, job execute log id: [{0}]", jobId), e);
            }

            @Override
            public void onExecuteTimeout(String jobId) {
                log.error("Job execute timeout, job execute log id:[{}]", jobId);
            }

        };

        public void setChildrenJob(List<MonitorRequest> childrenJob) {
            Assert.notEmpty(childrenJob, "Children jobs is empty.");
            childrenJob.stream().forEach(monitorRequest -> this.addChildJob(monitorRequest));
        }

        public synchronized void addChildJob(MonitorRequest child) {
            Assert.notNull(child, "Monitor request is null");
            if (CollectionUtils.isEmpty(childrenJob)) {
                this.childrenJob = new ArrayList<>();
            }
            this.childrenJob.add(child);
        }

        @Override
        public MonitorRequest clone() {
            MonitorRequest clone = new MonitorRequest(executeJobId, host, port, token, null, resultCallback);
            if (!CollectionUtils.isEmpty(this.childrenJob)) {
                List<MonitorRequest> cloneChildren = new ArrayList<>(this.childrenJob.size() * 4 / 3);
                this.childrenJob.stream().forEach(monitorRequest -> cloneChildren.add(monitorRequest.clone()));
                clone.setChildrenJob(cloneChildren);
            }
            return clone;
        }
    }

    @Getter
    @Setter
    @ToString(callSuper = true)
    class MonitorJobInfo extends MonitorRequest {
        // 监控请求时间
        private Long requestTime;
        // 超时时间
        private Long timeout;

        // 开启监控
        private Boolean monitor;
        // 已处理
        private Boolean processed;
    }

    @Getter
    @Setter
    @ToString(callSuper = true)
    class PreMonitorJobInfo extends MonitorRequest {
        // 监控信息是否已消费
        private boolean processed = false;
    }

    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    class MonitorJobResult {
        // 任务 Id
        private String jobId;
        // 执行结果
        private ExecuteResult executeResult;
    }

}
